/*
 * listener.c
 *
 * This file contains the source code for the event listener interface.
 * Functions that rely on being triggered when certain actions take place can
 * register themselves through this interface, and when the appropriate action
 * happens they will be called.
 */

#include <stdio.h>
#include <stdlib.h>
#include <utils/error.h>
#include "listener.h"

#define LISTENER_LIST_SIZE 10

/*
 * List of registered listener types.
 */
static listener* listener_list[LISTENER_LIST_SIZE];

static unsigned int l_init = 0;

/*
 * Initializes the listener interface.
 */
int listener_init() {
    int i;
    for( i = 0; i < LISTENER_LIST_SIZE; i++ ) {
        listener_list[i] = NULL;
    }
    l_init = 1;
    return 0;
}

/*
 * Creates a new listener with no registered listeners.
 */
listener * listener_create( event_t type ) {
    listener *list;
    struct listener_node *node;

    list = (listener*)malloc(sizeof(listener));
    node = (struct listener_node*)malloc(sizeof(struct listener_node));
    node->on_event = &free_event; /* Need to free event after it's handled */
    node->next = NULL;
    list->head = node;
    listener_list[type] = list;
    return list;
}

/*
 * Registers the given event handler for the given listener.
 * A new listener_node is created for the function and added to the list.
 */
void listener_register( event_t type, void (*on_event)(event*) ) {
    struct listener_node *node;

    if( listener_list[type] == NULL ) {
        listener_create(type);
    }
    node = (struct listener_node*)malloc(sizeof(struct listener_node));
    node->on_event = *on_event;
    node->next = listener_list[type]->head;
    listener_list[type]->head = node;
}

/*
 * Frees the given listener structure and all listener_nodes in the given
 * listener's list.
 */
void listener_free(listener *list) {
    struct listener_node *l1;
    struct listener_node *l2;
    if( list != NULL ) {
        l1 = list->head;
        while(l1) {
            l2 = l1;
            l1 = l1->next;
            free(l2);
        }
        free(list);
    }
    else {
        printerr( WARNING_CONT_LISTFREE );
    }
}

/*
 * Calls all event handlers in the given listener.
 */
void listener_inform( event *e ) {
    struct listener_node *l;
    if( listener_list[e->type] != NULL && e != NULL ) {
        l = listener_list[e->type]->head;
        while(l) {
            l->on_event(e);
            l = l->next;
        }
    }
    else {
        printerr( WARNING_CONT_LISTREG );
    }
}
